package org.zbclan.bf2.rcon.home.client.gpo;

import java.util.HashMap;
import java.util.List;

import net.customware.gwt.dispatch.client.DispatchAsync;
import net.customware.gwt.presenter.client.DisplayCallback;
import net.customware.gwt.presenter.client.EventBus;
import net.customware.gwt.presenter.client.place.Place;
import net.customware.gwt.presenter.client.place.PlaceChangedEvent;
import net.customware.gwt.presenter.client.place.PlaceRequest;
import net.customware.gwt.presenter.client.widget.WidgetPresenter;

import org.vaadin.gwtgraphics.client.DrawingArea;
import org.zbclan.bf2.rcon.common.shared.Bf2Object;
import org.zbclan.bf2.rcon.common.shared.Bf2Property;
import org.zbclan.bf2.rcon.common.shared.CombatArea;
import org.zbclan.bf2.rcon.common.shared.CombatAreaManager;
import org.zbclan.bf2.rcon.common.shared.ControlPoints;
import org.zbclan.bf2.rcon.common.shared.GamePlayObject;
import org.zbclan.bf2.rcon.common.shared.ObjectSpawner;
import org.zbclan.bf2.rcon.common.shared.ObjectTemplate;
import org.zbclan.bf2.rcon.home.client.event.GamePlayObjectReadyEvent;
import org.zbclan.bf2.rcon.home.client.event.GamePlayObjectReadyEventHandler;
import org.zbclan.bf2.rcon.home.shared.GetGamePlayObjectCommand;
import org.zbclan.bf2.rcon.home.shared.GetGamePlayObjectResult;
import org.zbclan.bf2.rcon.home.shared.SaveGamePlayObjectCommand;
import org.zbclan.bf2.rcon.home.shared.SaveGamePlayObjectResult;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HTMLTable.Cell;
import com.google.gwt.user.client.ui.RootLayoutPanel;
import com.google.inject.Inject;

public class GPOPresenter extends WidgetPresenter<GPODisplay> {

	public static final Place PLACE = new Place("gpo");

	private DispatchAsync dispatcher;

	private String name;

	private String mode;

	private GamePlayObject gpo;

	private HashMap<Bf2Object, Bf2Object> objectCpMap;

	@Inject
	public GPOPresenter(GPODisplay display, EventBus eventBus,
			DispatchAsync dispatcher) {

		super(display, eventBus);

		this.dispatcher = dispatcher;

		return;
	}

	@Override
	public Place getPlace() {
		return PLACE;
	}

	@Override
	protected void onBind() {

		eventBus.addHandler(GamePlayObjectReadyEvent.TYPE,
				new GamePlayObjectReadyEventHandler() {

					public void onGamePlayObjectReady(GamePlayObject gpo) {

						ObjectSpawner objectSpawner = gpo.getObjectSpawner();
						List<Bf2Object> objects = objectSpawner.getObjects();

						bindObjectEnabledChangeHandlers(objects);
						// bindTemplateClickHandlers(objects);
						bindControlPointClickHandlers(objects,
								gpo.getControlPoints());
						bindObjectClickHandlers(objects);

						GPOPresenter.this.gpo = gpo;

						return;
					}

				});

		display.getSaveClickable().addClickHandler(new ClickHandler() {

			public void onClick(ClickEvent event) {

				// boolean f = false;
				// List<Bf2Object> list = gpo.getObjectSpawner().getObjects();
				// for (Bf2Object obj2 : list) {
				// if (!obj2.isEnabled()) {
				// f = true;
				// }
				// }
				// if (!f) {
				// Window.alert("sdfs");
				// }

				SaveGamePlayObjectCommand cmd = new SaveGamePlayObjectCommand();
				cmd.setGpo(gpo);
				cmd.setUri(name + "/" + mode);

				DisplayCallback<SaveGamePlayObjectResult> callback = new DisplayCallback<SaveGamePlayObjectResult>(
						display) {

					@Override
					protected void handleFailure(Throwable e) {
						// TODO Auto-generated method stub

					}

					@Override
					protected void handleSuccess(SaveGamePlayObjectResult value) {
						Window.alert("saved");
					}
				};

				dispatcher.execute(cmd, callback);

				return;
			}
		});

		return;
	}

	protected void bindObjectClickHandlers(final List<Bf2Object> objects) {

		final FlexTable objectFlexTable = display.getObjectFlexTable();
		objectFlexTable.addClickHandler(new ClickHandler() {

			public void onClick(ClickEvent event) {
				Cell cell = objectFlexTable.getCellForEvent(event);
				Bf2Object key = objects.get(cell.getRowIndex() - 1);
				display.highlightObject(key);
				display.highlightControlPoint(objectCpMap.get(key));
			}
		});

		// for (final Bf2Object obj : objects) {
		// display.getMapObjectClickable(obj).addClickHandler(
		// new ClickHandler() {
		//
		// public void onClick(ClickEvent event) {
		// display.highlightObject(obj);
		// }
		// });
		// }

		return;
	}

	private void bindControlPointClickHandlers(List<Bf2Object> objects,
			ControlPoints controlPoints) {

		final HashMap<String, String> id_name_map = new HashMap<String, String>();
		for (ObjectTemplate cpot : controlPoints.getTemplates()) {
			HashMap<String, String> name_value_map = new HashMap<String, String>();
			for (Bf2Property p : cpot.getProperties().values()) {
				name_value_map.put(p.getName(), p.getValue());
			}
			id_name_map.put(
					name_value_map.get("ObjectTemplate.controlPointId"),
					name_value_map.get("ObjectTemplate.setControlPointName"));
		}

		final HashMap<String, Bf2Object> name_object_map = new HashMap<String, Bf2Object>();
		for (Bf2Object obj : controlPoints.getObjects()) {
			name_object_map.put(obj.getCreate(), obj);
		}

		objectCpMap = new HashMap<Bf2Object, Bf2Object>();
		for (Bf2Object obj : objects) {
			String controlPointId = obj.getSetControlPointId();
			String name = id_name_map.get(controlPointId);
			Bf2Object cp = name_object_map.get(name);
			objectCpMap.put(obj, cp);
		}

		for (final Bf2Object obj : objects) {
			display.getControlPointClickable(obj).addClickHandler(
					new ClickHandler() {

						public void onClick(ClickEvent event) {
							// Window.alert(obj.getSetControlPointId());
							// String controlPointId =
							// obj.getSetControlPointId();
							// String name = id_name_map.get(controlPointId);
							// Object key = name_object_map.get(name);
							// display.highlightControlPoint(key);
							display.highlightControlPoint(objectCpMap.get(obj));
						}
					});
		}

		return;
	}

	private void bindTemplateClickHandlers(List<Bf2Object> objects) {

		for (final Bf2Object obj : objects) {
			display.getTemplateClickable(obj).addClickHandler(
					new ClickHandler() {

						public void onClick(ClickEvent event) {
							Window.alert(obj.getCreate());
						}
					});
		}

		return;
	}

	private void bindObjectEnabledChangeHandlers(List<Bf2Object> objects) {

		for (final Bf2Object obj : objects) {
			display.getEnabledChangeable(obj).addValueChangeHandler(
					new ValueChangeHandler<Boolean>() {

						public void onValueChange(
								ValueChangeEvent<Boolean> event) {
							obj.setEnabled(event.getValue());
							// Window.alert(event.getValue() + "");
						}
					});
		}

		return;
	}

	@Override
	protected void onPlaceRequest(PlaceRequest request) {

		eventBus.fireEvent(new PlaceChangedEvent(request));

		name = request.getParameter("name", null);
		mode = request.getParameter("mode", null);
		/*
		 * #gpo;name=dalian_plant;mode=gpm_cq/16
		 */
		// Window.alert(name + " " + mode);

		refreshDisplay();

		RootLayoutPanel root = RootLayoutPanel.get();
		root.clear();
		root.add(getDisplay().asWidget());

		return;
	}

	@Override
	protected void onUnbind() {
	}

	public void refreshDisplay() {

		/*
		 * TODO get level properties
		 */
		GetGamePlayObjectCommand cmd = new GetGamePlayObjectCommand();
		cmd.setName(name);
		cmd.setMode(mode);

		DisplayCallback<GetGamePlayObjectResult> callback = new DisplayCallback<GetGamePlayObjectResult>(
				display) {

			@Override
			protected void handleFailure(Throwable e) {
				Window.alert(e.getMessage());
			}

			@Override
			protected void handleSuccess(GetGamePlayObjectResult value) {

				GamePlayObject gpo = value.getGamePlayObject();

				adjustCoordinates(gpo);

				DrawingArea mapDrawingArea = display.getMapDrawingArea();

				// display.clearMap();
				mapDrawingArea.clear();

				drawArea(gpo.getCombatAreaManager(), mapDrawingArea);
				drawObject(gpo.getObjectSpawner(), mapDrawingArea);
				drawControlPoint(gpo.getControlPoints(), mapDrawingArea);

				// mapSurface.translate((xMin + xMax) / 2, (yMin + yMax) / 2);
				// mapSurface.scale(Math.max(xMax - xMin, yMax - yMin) / 400);

				eventBus.fireEvent(new GamePlayObjectReadyEvent(gpo));

				return;
			}

		};

		dispatcher.execute(cmd, callback);

		return;
	}

	private void adjustCoordinates(GamePlayObject gpo) {

		float xMin = Float.MAX_VALUE;
		float xMax = Float.MIN_VALUE;
		float yMin = Float.MAX_VALUE;
		float yMax = Float.MIN_VALUE;

		ObjectSpawner objectSpawner = gpo.getObjectSpawner();
		List<Bf2Object> objects = objectSpawner.getObjects();
		for (Bf2Object obj : objects) {
			String[] coor = obj.getAbsolutePosition().split("/");
			float x = Float.parseFloat(coor[0]);
			// float z = Float.parseFloat(coor[1]);
			float y = Float.parseFloat(coor[2]);

			if (xMin > x) {
				xMin = x;
			}
			if (xMax < x) {
				xMax = x;
			}
			if (yMin > y) {
				yMin = y;
			}
			if (yMax < y) {
				yMax = y;
			}
		}

		CombatAreaManager combatAreaManager = gpo.getCombatAreaManager();
		for (CombatArea area : combatAreaManager.getAreas()) {

			List<String> areaPoints = area.getAreaPoints();
			int size = areaPoints.size();
			if (size > 0) {
				// -49.101013/-466.630981
				String point = areaPoints.get(0);
				String[] coor = point.split("/");
				float x = Float.parseFloat(coor[0]);
				float y = Float.parseFloat(coor[1]);

				// xMin = x;
				// xMax = x;
				// yMin = y;
				// yMax = y;
				if (xMin > x) {
					xMin = x;
				}
				if (xMax < x) {
					xMax = x;
				}
				if (yMin > y) {
					yMin = y;
				}
				if (yMax < y) {
					yMax = y;
				}

				for (int i = 1; i < size; i++) {
					point = areaPoints.get(i);
					coor = point.split("/");
					x = Float.parseFloat(coor[0]);
					y = Float.parseFloat(coor[1]);

					if (xMin > x) {
						xMin = x;
					}
					if (xMax < x) {
						xMax = x;
					}
					if (yMin > y) {
						yMin = y;
					}
					if (yMax < y) {
						yMax = y;
					}
				}
			}
		}

		// // mapSurface.scale(.25);
		// float k = 400 / Math.max(xMax - xMin, yMax - yMin);
		// mapSurface.translate(200 - (xMin + xMax) / 2 * k, 400 + (yMin + yMax)
		// / 2 * k);
		// // Window.alert((yMin + yMax) / 2 * k + "");
		// mapSurface.scale(k);

		float scale = 400f / Math.max(xMax - xMin, yMax - yMin);
		float xCenter = 200f - (xMin + xMax) / 2 * scale;
		float yCenter = 200f + (yMin + yMax) / 2 * scale;

		display.adjustCoordinates(scale, xCenter, yCenter);

		return;
	}

	protected void drawControlPoint(ControlPoints controlPoints,
			DrawingArea mapDrawingArea) {

		List<Bf2Object> objects = controlPoints.getObjects();
		for (Bf2Object obj : objects) {
			display.addControlPoint(obj, obj.getCreate(),
					obj.getAbsolutePosition(), obj.getLayer(), obj.isEnabled());

		}

		return;
	}

	private void drawObject(ObjectSpawner objectSpawner,
			DrawingArea mapDrawingArea) {

		/*
		 * TODO template lookup
		 */
		HashMap<String, HashMap<String, Bf2Property>> tMap = new HashMap<String, HashMap<String, Bf2Property>>();
		for (ObjectTemplate t : objectSpawner.getTemplates()) {
			HashMap<String, Bf2Property> map = new HashMap<String, Bf2Property>();
			for (Bf2Property p : t.getProperties().values()) {
				map.put(p.getName(), p);
			}
			String templateId = map.get("ObjectTemplate.create ObjectSpawner")
					.getValue();
			tMap.put(templateId, map);
		}

		// DirectShapeRenderer objectRenderer = new DirectShapeRenderer(
		// mapDrawingArea);
		// objectRenderer.beginPath();

		List<Bf2Object> objects = objectSpawner.getObjects();
		for (Bf2Object obj : objects) {
			HashMap<String, Bf2Property> map = tMap.get(obj.getCreate());
			String t1 = objectTypeForTeam(map,
					"ObjectTemplate.setObjectTemplate 1");
			String t2 = objectTypeForTeam(map,
					"ObjectTemplate.setObjectTemplate 2");
			display.addObject(obj, obj.getCreate(), t1, t2, obj.getLayer(),
					obj.getAbsolutePosition(), obj.getRotation(),
					obj.getSetControlPointId(), obj.isEnabled());

			// String[] coor = obj.getAbsolutePosition().split("/");
			// float x = Float.parseFloat(coor[0]);
			// // float z = Float.parseFloat(coor[1]);
			// float y = Float.parseFloat(coor[2]);
			//
			// // display.drawObject(x, y, z);
			// // objectRenderer.drawCircle(x * scale + xCenter,
			// // -y * scale + yCenter, 1);
			// Circle objShape = new Circle((int) (x * scale + xCenter), (int)
			// (-y
			// * scale + yCenter), 1);
			// mapDrawingArea.add(objShape);
		}

		// objectRenderer.closePath().stroke();

		return;
	}

	private String objectTypeForTeam(HashMap<String, Bf2Property> map,
			String propertyName) {

		String result;

		Bf2Property t = map.get(propertyName);
		if (t != null) {
			result = t.getValue();
			if (result.matches("ars_d30|ARS_D30|usart_lw155|USART_LW155")) {
				result = "Artilary";
			} else if (result
					.matches("aircontroltower_mec|aircontroltower_chi|aircontroltower")) {
				result = "UAV";
			} else if (result
					.matches("mobileradar_ch_dest|mobileradar_mech_dest|mobileradar_us_dest")) {
				result = "Radar";
			} else if (result.matches("wasp_defence_back|wasp_defence_front")) {
				result = "Phalanx";
			} else if (result.matches("CH_BIPOD|mec_bipod|MEC_BIPOD|US_BIPOD")) {
				result = "Bipod";
			} else if (result.matches("ats_tow|ATS_TOW|ats_hj8|ATS_HJ8")) {
				result = "Anti Tank Stationary";
			} else if (result
					.matches("usaas_stinger|USAAS_STINGER|igla_djigit|IGLA_DJIGIT")) {
				result = "Anti Air Stationary";
			} else if (result.matches("boat_rib|BOAT_RIB")) {
				result = "Boat";
			} else if (result
					.matches("jep_vodnik|JEP_VODNIK|jep_nanjing|JEP_NANJING|usjep_hmmwv|USJEP_HMMWV")) {
				result = "Heavy Jeep";
			} else if (result
					.matches("jep_mec_paratrooper|JEP_MEC_PARATROOPER|jep_paratrooper|JEP_PARATROOPER|jeep_faav|JEEP_FAAV")) {
				result = "Light Jeep";
			} else if (result
					.matches("ustnk_m1a2|USTNK_M1A2|tnk_type98|TNK_TYPE98|rutnk_t90|RUTNK_T90")) {
				result = "Tank";
			} else if (result
					.matches("usapc_lav25|USAPC_LAV25|apc_wz551|APC_WZ551|apc_btr90|APC_BTR90")) {
				result = "APC";
			} else if (result
					.matches("aav_type95|AAV_TYPE95|aav_tunguska|AAV_TUNGUSKA|usaav_m6|USAAV_M6")) {
				result = "Anti-Air Vehicle";
			} else if (result
					.matches("USAIR_F18|air_f35b|AIR_F35B|air_j10|AIR_J10|ruair_mig29|RUAIR_MIG29")) {
				result = "Fighter";
			} else if (result
					.matches("USAIR_F15|air_su30mkk|ruair_su34|RUAIR_SU34")) {
				result = "Bomber";
			} else if (result
					.matches("ahe_z10|AHE_Z10|ahe_havoc|AHE_HAVOC|ahe_ah1z|AHE_AH1Z")) {
				result = "Attack Helicopter";
			} else if (result
					.matches("chthe_z8|CHTHE_Z8|the_mi17|THE_MI17|usthe_uh60|USTHE_UH60")) {
				result = "Transport Helicopter";
			}
		} else {
			result = "";
		}

		return result;
	}

	private void drawArea(CombatAreaManager combatAreaManager,
			DrawingArea mapDrawingArea) {

		for (CombatArea area : combatAreaManager.getAreas()) {
			List<String> areaPoints = area.getAreaPoints();
			display.addArea(areaPoints);
			// int size = areaPoints.size();
			// if (size > 0) {
			//
			// // display.createArea(area.getCreate());
			// // DirectShapeRenderer areaRenderer = new DirectShapeRenderer(
			// // mapDrawingArea);
			//
			// // -49.101013/-466.630981
			// String point = areaPoints.get(0);
			// String[] coor = point.split("/");
			// float x = Float.parseFloat(coor[0]);
			// float y = Float.parseFloat(coor[1]);
			//
			// // display.beginArea(x, y);
			// // areaRenderer.beginPath().moveTo(x * scale + xCenter,
			// // -y * scale + yCenter);
			// Path areaShape = new Path((int) (x * scale + xCenter),
			// (int) (-y * scale + yCenter));
			//
			// for (int i = 1; i < size; i++) {
			// point = areaPoints.get(i);
			// coor = point.split("/");
			// x = Float.parseFloat(coor[0]);
			// y = Float.parseFloat(coor[1]);
			//
			// // display.addAreaPoint(x, y);
			// // areaRenderer.drawLineTo(x * scale + xCenter, -y * scale
			// // + yCenter);
			// areaShape.lineTo((int) (x * scale + xCenter), (int) (-y
			// * scale + yCenter));
			// }
			//
			// // display.closeArea();
			// // areaRenderer.closePath().stroke();
			// areaShape.close();
			// mapDrawingArea.add(areaShape);
			// }
		}

		return;
	}

	public void revealDisplay() {
	}

}
